`timescale 1ns/1ns
`ifndef ESPI_HARNESS
`define ESPI_HARNESS

`include "../../src/Macro.v"

logic		sys_clk	= 1'b1		;
logic		sys_rst_n = 1'b1	;
logic		espi_rst_n = 1'b1	;
logic		espi_cs = 1'b1	;
logic		espi_clk = 1'b0	;
logic [3:0]	send_data = 4'bzzzz	;
logic		wr_valid = 1'b0	;
//vw 
logic [7:0]	vw_irq0			;
                 
logic [7:0]	vw_irq1			;
                 
wire		slp_s3_n		;
wire		slp_s4_n		;
wire		slp_s5_n		;
                 
wire		oob_rst_warn	;
wire		sus_stat_n		;
wire		pltrst_n		;
                 
logic		pme_n = 1'b0	;
logic		wake_n = 1'b0	;
logic		oob_rst_ack	= 1'b0	;
                 
logic		slave_boot_load_status = 1'b0	;
logic		error_nonfatal = 1'b0	;
logic		error_fatal = 1'b0	;
logic		slave_boot_load_done = 1'b0	;
                 
logic		host_rst_ack = 1'b0	;
logic		pcin_n = 1'b0	;
logic		smi_n = 1'b0	;
logic		sci_n = 1'b0	;
                 
wire		nmiout_n		;
wire		smiout_n		;
wire		host_rst_warn	;

//drive interface
logic [5:0]		status_avail = 5'd0			;
logic [7:0]		cycle_to_ip = 8'h00			;
logic [3:0]		tag_to_ip = 4'h0				;
logic [11:0]	length_to_ip = 12'd0			;
logic [7:0]		code_to_ip = 8'h00		;
logic [31:0]	specific_to_ip = 32'd0	;
logic [7:0]		count_to_ip = 8'd0			;
logic			vw_group_req				;
logic [7:0]		vw_index_to_ip				;
logic [7:0]		vw_data_to_ip				;
logic [63:0]	addr_to_ip = 64'd0			;
logic [7:0]		SMBus_addr_to_ip = 0		;
logic [7:0]		SMBus_cmd_to_ip	= 0			;
logic [7:0]		SMBus_cnt_to_ip = 0		;
logic			data_req					;
logic [7:0]		data_to_ip = 8'h00			;

logic			command_valid	;
logic [7:0]		wr_command		;
logic [2:0]		addr_valid		;
logic [63:0]	address			;
logic			hdr_valid		;
logic [7:0]		cycle			;
logic [3:0]		tag				;
logic [11:0]	length			;
logic			message_valid	;
logic [7:0]		message_code	;
logic [31:0]	message_specific;
logic			vw_cnt_valid	;
wire  [7:0]		count			;
logic			vw_group_valid	;
logic [7:0]		vw_index		;
logic [7:0]		vw_data			;
logic			SMBus_hdr_valid	;
logic [7:0]		SMBus_target_addr;
logic [7:0]		SMBus_command	;
logic [7:0]		SMBus_byte_cnt	;
logic			data_valid		;
logic [7:0]		data_from_ip	;
logic			error_en		;
logic [15:0]	error_data		;
logic			response_wait = 0	;
logic			response_defer = 0	;
byte unsigned command;
byte unsigned set_reg_conf[2];
byte unsigned set_reg_data[4];

wire [3:0]	espi_data	;

/******************************************************************
	Bus-Functional Models
*******************************************************************/
//system reset task
task system_reset();
	sys_rst_n = 1'b1;
	#60 sys_rst_n = 1'b0;
	#100 sys_rst_n = 1'b1;
endtask

//randmozier 
/**************************************************************
command randc cycle address 
**************************************************************/
class rand_value;
	randc byte unsigned cycle_c,addr_c[],specific_c[],code_c[],count_c,data_c[],register_addr_c[2],short_addr_c[],short_data_c[],short_c,vw_data_c,vw_index_c;
	randc byte unsigned SMBus_addr_c,SMBus_cmd_c,SMBus_byte_cnt_c,put_cycle_c,put_data_c[],completion_c;
	rand bit [11:0] length_c;
	rand bit [11:0] put_length_c;
	rand bit [3:0]	tag_c;
	constraint cycle_randc
	{
		if(command == 8'h00)
			{cycle_c inside {8'h01,8'h03,8'h10,8'h11,8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};}
		else if(command == 8'h01)
			{cycle_c inside {8'h01,8'h03,8'h10,8'h11,8'h06,8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};}
		else if(command == 8'h02 || command == 8'h03)
			{cycle_c inside {8'h00,8'h02};}
		else if(command == 8'h06 || command == 8'h07)
			{cycle_c inside {8'h21};}
		else if(command == 8'h09)
			{cycle_c inside {8'h00,8'h01,8'h02};}
		else if(command == 8'h0a)
			{cycle_c inside {8'h00,8'h01,8'h02,8'h03,8'h23,8'h43,8'h63,8'h04,8'h24,8'h44,8'h64};}
		else if(command == 8'h08 || command == 8'h0b)
			{cycle_c inside {8'h06,8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};}
		else
			{cycle_c inside {8'hff};}
	}
	constraint length_rand {length_c > 3 && length_c <= 20;};
	constraint addr_randc
	{
		if(cycle_c == 8'h00 || cycle_c == 8'h01)
		{
			addr_c.size() inside {4};
			specific_c.size() inside {0};
			code_c.size() inside {0};
		}
		else if(cycle_c == 8'h02 || (command == 8'h00 && cycle_c == 8'h03))
		{
			addr_c.size() inside {8};
			specific_c.size() inside {0};
			code_c.size() inside {0};
		}
		else if(cycle_c == 8'h10 || cycle_c == 8'h11)
		{
			addr_c.size() inside {0};
			specific_c.size() inside {4};
			code_c.size() inside {1};
		}
		else
		{
			addr_c.size() inside {0};
			specific_c.size() inside {0};
			code_c.size() inside {0};
		}
	}
	constraint count_rand
	{
		if(command == 8'h04 || command == 8'h05)
			count_c inside {count_c > 0 && count_c <= 7};
		else
			count_c inside {0};
	}
	constraint data_rand
	{
		if(cycle_c == 8'h10 || cycle_c == 8'h08 || cycle_c == 8'h0a || cycle_c == 8'h0c || cycle_c == 8'h0e || cycle_c == 8'h00 || cycle_c == 8'h02 || cycle_c == 8'h06 || cycle_c == 8'h04 || cycle_c == 8'h24 || cycle_c == 8'h44 || cycle_c == 8'h64)
			data_c.size() inside {0};
		else if(cycle_c == 8'h21)
			data_c.size() inside {result(length_c)};
		else
			data_c.size() inside {length_c};
	}
	constraint register_randc
	{
		register_addr_c[0] inside {8'h00};
		register_addr_c[1] inside {8'h01,8'h04,8'h08,8'h10,8'h20,8'h30,8'h40};
	}
	constraint short_randc
	{
		short_c inside {8'h40,8'h41,8'h43,8'h44,8'h45,8'h47,8'h48,8'h49,8'h4b,8'h4c,8'h4d,8'h4f};
	}
	constraint short_addr_randc
	{
		if(short_c == 8'h40 || short_c == 8'h41 || short_c == 8'h43 || short_c == 8'h44 || short_c == 8'h45 || short_c == 8'h47)
		{
			short_addr_c.size() inside {2};
		}
		else if(short_c == 8'h48 || short_c == 8'h49 || short_c == 8'h4b || short_c == 8'h4c || short_c == 8'h4d || short_c == 8'h4f)
		{
			short_addr_c.size() inside {4};
		}
		else
		{
			short_addr_c.size() inside {0};
		}
	}
	constraint short_data_rand
	{
		//if(short_c == 8'h40 || short_c == 8'h44 || short_c == 8'h48 || short_c == 8'h4c)
		if(short_c == 8'h44 || short_c == 8'h4c)
			short_data_c.size() inside {1};
		else if( short_c == 8'h45 || short_c == 8'h4d)
			short_data_c.size() inside {2};
		else if(short_c == 8'h47 || short_c == 8'h4f)
			short_data_c.size() inside {4};
		else
			short_data_c.size() inside {0};
	}
	constraint count_index_randc
	{
		if(command == 8'h04)
		{
			vw_data_c inside {8'h77,8'h70,8'h07};
			vw_index_c inside {8'h02,8'h03,8'h04};
		}
		else if(command == 8'h05)
		{
			vw_data_c inside {8'hff,8'hf0,8'h0f};
			vw_index_c inside {8'h00,8'h01,8'h04,8'h05,8'h06};
		}
		else
		{
			vw_data_c inside {0};
			vw_index_c inside {0};
		}
	}
	constraint put_randc
	{
		if(command == 8'h02 || command == 8'h0a)
		{
			put_cycle_c inside {8'h06,8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};
		}
		else
		{
			put_cycle_c inside {8'h06};
		}
	}
	constraint put_length_randc {put_length_c > 2 && put_length_c <= 20;};
	constraint SMBus_byte_cnt_randc
	{
		SMBus_byte_cnt_c == result(length_c);
	}
	function byte unsigned result(bit [11:0] lengt);
		result = lengt - 3;
	endfunction
	constraint completion_randc
	{
		completion_c inside {8'h06,8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};
	}
endclass

rand_value updata = new();

//espi interface class
//espi reset start end read write task
class espi_base;
	task espi_reset();
		espi_rst_n = 1'b1;
		#100 espi_rst_n = 1'b0;
		#100 espi_rst_n = 1'b1;
	endtask
	task espi_start();
		espi_cs = 1'b1;
		#10
		espi_cs = 1'b0;
		wr_valid = 1;
	endtask
	task espi_end();
		#50 espi_cs = 1'b1;
		#100;
	endtask
	task espi_tar(int cycle,ref logic [3:0] data);
		for(int i=0;i<4;i++)
		begin
			unique case(i)
				0	:	data = 4'hf;
				2	:	data = 4'bzzzz;
				default	:	data = data;
			endcase
			#cycle espi_clk = ~espi_clk;
		end
		wr_valid = 0;
	endtask
	virtual task espi_write(int cycle,byte unsigned data_in[],ref logic [3:0]data);
	endtask
	virtual task espi_read(int cycle,output byte unsigned data_out);
	endtask
endclass

//command 
class command_package extends espi_base;
	task read_operation(int cycle,byte unsigned command,byte unsigned data_out[$]);
		byte unsigned length_t = 3,data,length_rd;
		for(int i=0;i<=length_t;i++)
		begin
			if(response_defer) length_t = 3;
			else
			begin
				unique case(command)
					8'h01,8'h02,8'h03,8'h07,8'h09,8'h0a,8'h0b	:
						unique case(cycle_to_ip)
							8'h00	:	length_t = 10;
							8'h01	:	length_t = length_to_ip + 10;
							8'h02	:	length_t = 14;
							8'h03	:	length_t = length_to_ip + 14;
							8'h10	:	length_t = 11;
							8'h11	:	length_t = length_to_ip + 11;
							8'h06,8'h08,8'h0a,8'h0c,8'h0e	:	length_t = 6;
							8'h09,8'h0b,8'h0d,8'h0f,8'h21	:	length_t = 6 + length_to_ip;
							default	:	length_t = length_t;
						endcase
					8'h05		:	length_t = 2*(count_to_ip+1)+4;
					8'h40,8'h48	:	length_t = 4;
					8'h41,8'h49	:	length_t = 5;
					8'h43,8'h4b,8'h21	:	length_t = 7;
					default	:	length_t = length_t;
				endcase
			end
			espi_read(cycle,data);
			data_out.push_back(data);
		end
	endtask

	task espi_espi_crc(int cycle,byte unsigned data_in[],ref logic [3:0] data);
		byte unsigned lfsr_c,lfsr_q,crc_value;
		lfsr_q = 8'h00;
		lfsr_c = 8'h00;
		foreach(data_in[i])
		begin
			lfsr_c[0] = lfsr_q[0] ^ lfsr_q[6] ^ lfsr_q[7] ^ data_in[i][0] ^ data_in[i][6] ^ data_in[i][7];     
			lfsr_c[1] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[6] ^ data_in[i][0] ^ data_in[i][1] ^ data_in[i][6];     
			lfsr_c[2] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[6] ^ data_in[i][0] ^ data_in[i][1] ^ data_in[i][2] ^ data_in[i][6];     
			lfsr_c[3] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[7] ^ data_in[i][1] ^ data_in[i][2] ^ data_in[i][3] ^ data_in[i][7];     
			lfsr_c[4] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ data_in[i][2] ^ data_in[i][3] ^ data_in[i][4];     
			lfsr_c[5] = lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ data_in[i][3] ^ data_in[i][4] ^ data_in[i][5];     
			lfsr_c[6] = lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ data_in[i][4] ^ data_in[i][5] ^ data_in[i][6];     
			lfsr_c[7] = lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ data_in[i][5] ^ data_in[i][6] ^ data_in[i][7];
			lfsr_q = lfsr_c;
			crc_value = lfsr_q;
		end
		espi_write(cycle,{crc_value},data);
	endtask

	task espi_mrg(int cycle,byte unsigned data_in[],ref byte unsigned data_out[$],ref logic [3:0] wr_data);
		espi_start();
		espi_write(cycle,data_in,wr_data);
		espi_espi_crc(cycle,data_in,wr_data);
		espi_tar(cycle,wr_data);
		read_operation(cycle,data_in[0],data_out);
		espi_end();
	endtask
	
	task set_configuration(int cycle,byte unsigned addr[2],data[4],ref logic [3:0] wr_data);
		byte unsigned data_out[$];
		command = 8'h22;
		espi_start();
		espi_write(cycle,{command,addr,data},wr_data);
		espi_espi_crc(cycle,{command,addr,data},wr_data);
		espi_tar(cycle,wr_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask
	
	task get_configuration(int cycle,byte unsigned addr[2],ref logic [3:0] wr_data);
		byte unsigned data_out[$];
		command = 8'h21;
		espi_start();
		espi_write(cycle,{command,addr},wr_data);
		espi_espi_crc(cycle,{command,addr},wr_data);
		espi_tar(cycle,wr_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_status(int cycle);
		byte unsigned data_out[$];
		command = 8'h25;
		espi_start();
		espi_write(cycle,{command},send_data);
		espi_espi_crc(cycle,{command},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_pc(int cycle,byte unsigned cycle_type,addr[],code[],specific[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		logic [15:0] tag_length = {tag,length};
		command = 8'h00;
		temp_data = {command,cycle_type,tag_length[15:8],tag_length[7:0],addr,code,specific,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_np(int cycle,byte unsigned cycle_type,addr[],code[],specific[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		logic [15:0] tag_length = {tag,length};
		command = 8'h02;
		temp_data = {command,cycle_type,tag_length[15:8],tag_length[7:0],addr,code,specific,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_pc(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h01;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_np(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h03;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_iord_short(int cycle,byte unsigned command,addr[2],ref logic [3:0] data);
		byte unsigned data_out[$];
		espi_start();
		espi_write(cycle,{command,addr},data);
		espi_espi_crc(cycle,{command,addr},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_iowr_short(int cycle,byte unsigned command,addr[2],data_in[],ref logic [3:0] data);
		byte unsigned data_out[$];
		espi_start();
		espi_write(cycle,{command,addr,data_in},data);
		espi_espi_crc(cycle,{command,addr,data_in},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_memrd32_short(int cycle,byte unsigned command,addr[4],ref logic [3:0] data);
		byte unsigned data_out[$];
		espi_start();
		espi_write(cycle,{command,addr},data);
		espi_espi_crc(cycle,{command,addr},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_memwr32_short(int cycle,byte unsigned command,addr[4],data_in[],ref logic [3:0] data);
		byte unsigned data_out[$];
		espi_start();
		espi_write(cycle,{command,addr,data_in},data);
		espi_espi_crc(cycle,{command,addr,data_in},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_vwire(int cycle,byte unsigned count,data_in[],ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		command = 8'h04;
		temp_data = {command,count,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_vwire(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h05;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_oob(int cycle,logic [3:0] tag,logic[11:0] length,byte unsigned cycle_type,SMBus_addr,SMBus_cmd,SMBus_cnt,data_in[],ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		logic [15:0] tag_length = {tag,length};
		command = 8'h06;
		temp_data = {command,cycle_type,tag_length[15:8],tag_length[7:0],SMBus_addr,SMBus_cmd,SMBus_cnt,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_oob(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h07;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_flash_c(int cycle,byte unsigned cycle_type,addr[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		logic [15:0] tag_length = {tag,length};
		command = 8'h08;
		temp_data = {command,cycle_type,tag_length[15:8],tag_length[7:0],addr,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_flash_np(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h09;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task put_flash_np(int cycle,byte unsigned cycle_type,addr[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
		byte unsigned data_out[$],temp_data[];
		logic [15:0] tag_length = {tag,length};
		command = 8'h0a;
		temp_data = {command,cycle_type,tag_length[15:8],tag_length[7:0],addr,data_in};
		espi_start();
		espi_write(cycle,temp_data,data);
		espi_espi_crc(cycle,temp_data,data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task get_flash_c(int cycle,ref logic [3:0] data);
		byte unsigned data_out[$];
		command = 8'h0b;
		espi_start();
		espi_write(cycle,{command},data);
		espi_espi_crc(cycle,{command},data);
		espi_tar(cycle,data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask
endclass

class component_packages extends command_package;
//channel independent
	task get_configuration_randc(int cycle);
		command = 8'h21;
		for(int i=0;i<=5;i++)
		begin
			updata.randomize();
			get_configuration(cycle,updata.register_addr_c,send_data);
		end
	endtask

	task eSPI_signal_initial(int cycle);
		set_reg_conf = {8'h00,8'h08};
		set_reg_data = {8'h0f,8'h00,8'h0c,8'h83};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	task eSPI_dual_initial(int cycle);
		set_reg_conf = {8'h00,8'h08};
		set_reg_data = {8'h0f,8'h00,8'h0c,8'h87};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask
	
	task eSPI_quad_initial(int cycle);
		set_reg_conf = {8'h00,8'h08};
		set_reg_data = {8'h0f,8'h00,8'h0c,8'h8b};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	task eSPI_peripheral_initial(int cycle);
		set_reg_conf = {8'h00,8'h10};
		set_reg_data = {8'h13,8'h11,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h20};
		set_reg_data = {8'h02,8'h07,8'h06,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h30};
		set_reg_data = {8'h12,8'h01,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h40};
		set_reg_data = {8'h26,8'h11,8'h03,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask
	
	task eSPI_vwire_initial(int cycle);
		set_reg_conf = {8'h00,8'h10};
		set_reg_data = {8'h12,8'h11,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h20};
		set_reg_data = {8'h03,8'h07,8'h06,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h30};
		set_reg_data = {8'h12,8'h01,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h40};
		set_reg_data = {8'h26,8'h11,8'h03,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	task eSPI_oob_initial(int cycle);
		set_reg_conf = {8'h00,8'h10};
		set_reg_data = {8'h12,8'h11,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h20};
		set_reg_data = {8'h02,8'h07,8'h06,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h30};
		set_reg_data = {8'h13,8'h01,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h40};
		set_reg_data = {8'h26,8'h11,8'h03,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	task eSPI_flash_initial(int cycle);
		set_reg_conf = {8'h00,8'h10};
		set_reg_data = {8'h12,8'h11,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h20};
		set_reg_data = {8'h02,8'h07,8'h06,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h30};
		set_reg_data = {8'h12,8'h01,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
		set_reg_conf = {8'h00,8'h40};
		set_reg_data = {8'h27,8'h11,8'h03,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	task IO_model_randc(int cycle);
		for(int i=0;i<= 5;i++)
		begin
			set_configuration(cycle,{8'h00,8'h08},{8'h0f,8'h00,8'h0c,8'h87},send_data);
			get_status(cycle);
		end
	endtask
//peripheral channel cycle types randc
//task put_pc(int cycle,byte unsigned cycle_type,addr[],code[],specific[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
	task put_pc_randc(int cycle);
		command = 8'h00;
		for(int i=0;i<=11;i++)
		begin
			updata.randomize();
			put_pc(cycle,updata.cycle_c,updata.addr_c,updata.code_c,updata.specific_c,updata.data_c,4'h0,updata.length_c,send_data);
		end
	endtask

//task put_np(int cycle,byte unsigned cycle_type,addr[],code[],specific[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
	task put_np_randc(int cycle);
		byte unsigned temp_data[];
		byte unsigned data_out[$];
		command = 8'h02;
		for(int i=0;i<=8;i++)
		begin
			updata.randomize();
			cycle_to_ip = updata.completion_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			put_np(cycle,updata.cycle_c,updata.addr_c,updata.code_c,updata.specific_c,updata.data_c,4'h0,updata.length_c,send_data);
		end
		updata.randomize();
		temp_data = {command,updata.cycle_c,8'h00,updata.length_c,updata.addr_c,updata.code_c,updata.specific_c,updata.data_c};
		espi_start();
		espi_write(cycle,temp_data,send_data);
		espi_espi_crc(cycle,temp_data,send_data);
		response_defer = 1;
		espi_tar(cycle,send_data);
		
		read_operation(cycle,command,data_out);
		response_defer = 0;
		espi_end();
	endtask

//task get_pc(int cycle,ref logic [3:0] data);
	task get_pc_randc(int cycle);
		command = 8'h01;
		for(int i=0;i<=12;i++)
		begin
			updata.randomize();
			status_avail = 6'b0000_01;
			get_status(cycle);
			status_avail = 6'b0000_00;
			cycle_to_ip = updata.cycle_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			foreach(updata.addr_c[i]) addr_to_ip = {addr_to_ip[55:0],updata.addr_c[i]};
			get_pc(cycle,send_data);
		end
	endtask

	task get_np_randc(int cycle);
		command = 8'h03;
		for(int i=0;i<=1;i++)
		begin
			updata.randomize();
			status_avail = 6'b0000_10;
			get_status(cycle);
			status_avail = 6'b0000_00;
			cycle_to_ip = updata.cycle_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			foreach(updata.addr_c[i]) addr_to_ip = {addr_to_ip[55:0],updata.addr_c[i]};
			get_np(cycle,send_data);
		end
	endtask

	task put_short_randc(int cycle);
		byte unsigned data_out[$];
		for(int i=0;i<=11;i++)
		begin
			updata.randomize();
			command = updata.short_c;
			espi_start();
			espi_write(cycle,{command,updata.short_addr_c,updata.short_data_c},send_data);
			espi_espi_crc(cycle,{command,updata.short_addr_c,updata.short_data_c},send_data);
			espi_tar(cycle,send_data);
			read_operation(cycle,command,data_out);
			espi_end();
			//espi_mrg(cycle,{updata.short_c,updata.short_addr_c,updata.short_data_c},data_out,send_data);
		end
	endtask

	task invalid_command_error(int cycle);
		byte unsigned data_out[$];
		espi_mrg(cycle,{8'hef},data_out,send_data);
		get_status(cycle);
	endtask

	task invalid_cycle_error(int cycle);
		byte unsigned data_out[$];
		espi_mrg(cycle,{8'h00,8'h5f,8'h00,8'h04},data_out,send_data);
		get_status(cycle);
	endtask

	task peripheral_crc_error(int cycle);
		byte unsigned data_out[$];
		command = 8'h25;
		espi_start();
		espi_write(cycle,{command},send_data);
		espi_espi_crc(cycle,{8'h08},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task unexpected_cs(int cycle);
		byte unsigned data_out[$];
		espi_start();
		espi_write(cycle,{8'h48,8'h88,8'h77,8'h66,8'h55},send_data);
		espi_start();
		espi_espi_crc(cycle,{8'h48,8'h88,8'h77,8'h66,8'h55},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task peripheral_protocal_error(int cycle);
		get_np(cycle,send_data);
		get_pc(cycle,send_data);
	endtask
	//espi_mrg(int cycle,byte unsigned data_in[],ref byte unsigned data_out[$],ref logic [3:0] wr_data);
	task peripheral_malforned_packet(int cycle);
		byte unsigned data_out[$],data_in[];
		data_in = new[65];
		foreach(data_in[i]) data_in[i] = i;
		data_in = {8'h00,8'h09,8'h00,8'h41,data_in};
		espi_mrg(cycle,data_in,data_out,send_data);
		data_in.delete();
		data_in = new[69];
		foreach(data_in[i]) data_in[i] = i;
		data_in = {8'h00,8'h09,8'h00,8'h45,data_in};
		espi_mrg(cycle,data_in,data_out,send_data);
		/*
		data_in.delete();
		data_in = new[4095];
		foreach(data_in[i]) data_in[i] = i;
		data_in = {8'h00,8'h01,8'h0f,8'hff,8'haa,8'hcc,8'hdd,8'h4f,data_in};
		$display("data in size %0h",data_in.size());
		espi_mrg(cycle,data_in,data_out,send_data);
		*/
	endtask

	task peripheral_unsupported_command(int cycle);
		get_flash_c(cycle,send_data);
	endtask

//put_pc(int cycle,byte unsigned cycle_type,addr[],code[],specific[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
	task peripheral_unsupported_cycle(int cycle);
		byte unsigned data_in[],data_out[$];
		command = 8'h00;
		data_in = {command,8'h21,8'h00,8'h01,8'h88};
		espi_mrg(cycle,data_in,data_out,send_data);
	endtask

	task peripheral_unsupported_message(int cycle);;
		put_pc(cycle,8'h10,{},{8'h02},{8'h22,8'h85,8'h8b,8'h10},{},4'h0,12'd1,send_data);
	endtask

	task peripheral_unsupported_length(int cycle);
		set_reg_conf = {8'h00,8'h10};
		set_reg_data = {8'h13,8'h21,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	//virtual wire channel command cycle types randc
	//task put_vwire(int cycle,byte unsigned count,data_in[],ref logic [3:0] data);
	task put_vwire_randc(int cycle);
		byte unsigned data_in[],count_index,count_data;
		command = 8'h04;
		for(int i=0;i<=2;i++)
		begin
			updata.randomize();
			data_in = {8'h02,updata.vw_data_c,8'h03,updata.vw_data_c,8'h07,updata.vw_data_c};
			put_vwire(cycle,8'h02,data_in,send_data);
			data_in.delete();
		end
		data_in = {8'h40,8'hef,8'h41,8'hde,8'h42,8'h5e};
		put_vwire(cycle,8'h02,data_in,send_data);
	endtask

	task get_vwire_randc(int cycle);
		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 0;
		vw_irq0 = 8'h55;
		get_vwire(cycle,send_data);
		
		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 1;
		vw_irq1 = 8'haa;
		get_vwire(cycle,send_data);

		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 4;
		pme_n = 1'b0;
		wake_n = 1'b1;
		oob_rst_ack = 1'b1;
		get_vwire(cycle,send_data);

		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 5;
		slave_boot_load_status = 1'b1;
		error_nonfatal = 1'b0;
		error_fatal = 1'b0;
		slave_boot_load_done = 1'b1;
		get_vwire(cycle,send_data);

		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 6;
		host_rst_ack = 1'b1;
		pcin_n = 1'b1;
		smi_n = 1'b0;
		sci_n = 1'b1;
		get_vwire(cycle,send_data);

		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 0;
		vw_index_to_ip = 7;
		vw_data_to_ip = 8'hef;
		get_vwire(cycle,send_data);

		status_avail = 6'b0001_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		count_to_ip = 1;
		vw_index_to_ip = 7;
		vw_data_to_ip = 8'hef;
		get_vwire(cycle,send_data);
	endtask
	
	task vw_crc_error(int cycle);
		byte unsigned data_out[$];
		command = 8'h05;
		espi_start();
		espi_write(cycle,{command},send_data);
		espi_espi_crc(cycle,{8'h08},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task vw_protocal_error(int cycle);
		get_vwire(cycle,send_data);
	endtask

	task vw_malformed_packet(int cycle);
		byte unsigned data_out[$],data_in[];
		command = 8'h04;
		data_in = {command,8'h09};
		for(int i=0;i<18;i++)
			data_in[i+2] = i;
		espi_mrg(cycle,data_in,data_out,send_data);
	endtask

	task vw_unsupported_command(int cycle);
		command = 8'h03;
		updata.randomize();
		status_avail = 6'b0000_10;
		get_status(cycle);
		status_avail = 6'b0000_00;
		get_np(cycle,send_data);
	endtask

	task vw_unpported_length(int cycle);
		set_reg_conf = {8'h00,8'h20};
		set_reg_data = {8'h02,8'h07,8'h07,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

	//oob channel command cycle types randc
	//put_oob(int cycle,logic [3:0] tag,logic[11:0] length,byte unsigned cycle_type,SMBus_addr,SMBus_cmd,SMBus_cnt,data_in[],ref logic [3:0] data);
	task put_oob_randc(int cycle);
		command = 8'h06;
		updata.randomize();
		put_oob(cycle,4'h0,updata.length_c,updata.cycle_c,updata.SMBus_addr_c,updata.SMBus_cmd_c,updata.SMBus_byte_cnt_c,updata.data_c,send_data);
	endtask

	task get_oob_randc(int cycle);
		command = 8'h07;
		updata.randomize();
		cycle_to_ip = updata.cycle_c;
		tag_to_ip = updata.tag_c;
		length_to_ip = updata.length_c;
		SMBus_addr_to_ip = updata.SMBus_addr_c;
		SMBus_cmd_to_ip = updata.SMBus_cmd_c;
		SMBus_cnt_to_ip = updata.SMBus_byte_cnt_c;
		status_avail = 6'b0010_00;
		get_status(cycle);
		status_avail = 6'b0000_00;
		get_oob(cycle,send_data);
	endtask
	
	task oob_crc_error(int cycle);
		byte unsigned data_out[$];
		command = 8'h06;
		espi_start();
		espi_write(cycle,{command},send_data);
		espi_espi_crc(cycle,{8'h08},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task oob_protocal_error(int cycle);
		get_oob(cycle,send_data);
	endtask

	task oob_malformed_packet(int cycle);
	endtask

	task oob_unsupported_command(int cycle);
		byte unsigned data_out[$];
		command = 8'h03;
		updata.randomize();
		status_avail = 6'b0000_10;
		get_status(cycle);
		status_avail = 6'b0000_00;
		get_np(cycle,send_data);
	endtask

	task oob_unsupported_cycle(int cycle);
		byte unsigned data_in[],data_out[$];
		command = 8'h06;
		data_in = {command,8'h09,8'h00,8'h01,8'h88};
		espi_mrg(cycle,data_in,data_out,send_data);
	endtask

	task oob_unpported_length(int cycle);
		set_reg_conf = {8'h00,8'h30};
		set_reg_data = {8'h13,8'h02,8'h00,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask

//flash channel command cycle types randc
//task put_flash_c(int cycle,byte unsigned cycle_type,addr[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
	task put_flash_c_randc(int cycle);
		command = 8'h08;
		for(int i=0;i<9;i++)
		begin
			updata.randomize();
			put_flash_c(cycle,updata.cycle_c,updata.addr_c,updata.data_c,4'h0,updata.length_c,send_data);
		end
	endtask

//task put_flash_np(int cycle,byte unsigned cycle_type,addr[],data_in[],logic [3:0] tag,logic [11:0] length,ref logic [3:0] data);
	task put_flash_np_randc(int cycle);
		command = 8'h0a;
		for(int i=0;i<11;i++)
		begin
			updata.randomize();
			cycle_to_ip = updata.completion_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			put_flash_np(cycle,updata.cycle_c,updata.addr_c,updata.data_c,4'h0,updata.length_c,send_data);
		end
	endtask

//task get_flash_np(int cycle,ref logic [3:0] data);
	task get_flash_c_randc(int cycle);
		command = 8'h0b;
		for(int i=0;i<9;i++)
		begin
			updata.randomize();
			status_avail = 6'b0100_00;
			get_status(cycle);
			status_avail = 6'b0000_00;
			cycle_to_ip = updata.cycle_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			get_flash_c(cycle,send_data);
		end
	endtask

	task get_flash_np_randc(int cycle);
		command = 8'h09;
		for(int i=0;i<3;i++)
		begin
			updata.randomize();
			status_avail = 6'b1000_00;
			get_status(cycle);
			status_avail = 6'b0000_00;
			cycle_to_ip = updata.cycle_c;
			tag_to_ip = updata.tag_c;
			length_to_ip = updata.length_c;
			foreach(updata.addr_c[i]) addr_to_ip = {addr_to_ip[55:0],updata.addr_c[i]};
			get_flash_np(cycle,send_data);
		end
	endtask

	task flash_crc_error(int cycle);
		byte unsigned data_out[$];
		command = 8'h08;
		espi_start();
		espi_write(cycle,{command},send_data);
		espi_espi_crc(cycle,{8'h09},send_data);
		espi_tar(cycle,send_data);
		read_operation(cycle,command,data_out);
		espi_end();
	endtask

	task flash_protocal_error(int cycle);
		get_flash_c(cycle,send_data);
		get_flash_np(cycle,send_data);
	endtask

	task flash_malformed_packet(int cycle);
	byte unsigned data_in[],data_out[$];
		command = 8'h0a;
		data_in = {command,8'h01,8'h00,8'h42};
		for(int i=0;i<66;i++)
			data_in[i+4] = i;
		espi_mrg(cycle,data_in,data_out,send_data);
	endtask

	task flash_unsupported_command(int cycle);
		byte unsigned data_out[$];
		command = 8'h03;
		updata.randomize();
		status_avail = 6'b0000_10;
		get_status(cycle);
		status_avail = 6'b0000_00;
		get_np(cycle,send_data);
	endtask

	task flash_unsupported_cycle(int cycle);
		byte unsigned data_in[],data_out[$];
		command = 8'h0b;
		data_in = {command,8'h21,8'h00,8'h01,8'h88};
		espi_mrg(cycle,data_in,data_out,send_data);
	endtask

	task flash_unpported_length(int cycle);
		set_reg_conf = {8'h00,8'h40};
		set_reg_data = {8'h27,8'h21,8'h03,8'h00};
		set_configuration(cycle,set_reg_conf,set_reg_data,send_data);
	endtask
endclass

class espi_single extends component_packages;
	virtual task espi_write(int cycle,byte unsigned data_in[],ref logic [3:0] data);
		espi_clk = 0;
		foreach(data_in[i])
		begin
			for(int j=0;j<16;j++)
			begin
				unique case(j)
					0	:	data[0] = data_in[i][7];
					2	:	data[0] = data_in[i][6];
					4	:	data[0] = data_in[i][5];
					6	:	data[0] = data_in[i][4];
					8	:	data[0] = data_in[i][3];
					10	:	data[0] = data_in[i][2];
					12	:	data[0] = data_in[i][1];
					14	:	data[0] = data_in[i][0];
					default :
						data = data;
				endcase
				#cycle espi_clk = ~espi_clk;
			end
		end
	endtask
	virtual task espi_read(int cycle,output byte unsigned data_out);
		espi_clk = 0;
		for(int i=0;i<16;i++)
		begin
			#cycle espi_clk = ~espi_clk;
			if(i % 2 != 0)
				data_out = {data_out[6:0],espi_data[0]};
			else
				data_out = data_out;
		end
	endtask
endclass

class espi_dual extends component_packages;
	virtual task espi_write(int cycle,byte unsigned data_in[],ref logic [3:0] data);
		espi_clk = 0;
		foreach(data_in[i])
		begin
			for(int j=0;j<8;j++)
			begin
				unique case(j)
					0	:	data[1:0] = data_in[i][7:6];
					2	:	data[1:0] = data_in[i][5:4];
					4	:	data[1:0] = data_in[i][3:2];
					6	:	data[1:0] = data_in[i][1:0];
					default :
						data = data;
				endcase
				#cycle espi_clk = ~espi_clk;
			end
		end
	endtask
	virtual task espi_read(int cycle,output byte unsigned data_out);
		espi_clk = 0;
		for(int i=0;i<8;i++)
		begin
			#cycle espi_clk = ~espi_clk;
			if(i%2 != 0)
				data_out = {data_out[5:0],espi_data[1:0]};
			else
				data_out = data_out;
		end
	endtask
endclass

class espi_quad extends component_packages;
	virtual task espi_write(int cycle,byte unsigned data_in[],ref logic [3:0] data);
		espi_clk = 0;
		foreach(data_in[i])
		begin
			//$display("input  data_in = %x",data_in[i]);
			for(int j=0;j<4;j++)
			begin
				unique case(j)
					0	:	data[3:0] = data_in[i][7:4];
					2	:	data[3:0] = data_in[i][3:0];
					default :	data = data;
				endcase
				//$display("output data = %x",data);
				#cycle espi_clk = ~espi_clk;
			end
		end
	endtask
	virtual task espi_read(int cycle,output byte unsigned data_out);
		espi_clk = 0;
		for(int i=0;i<4;i++)
		begin
			#cycle espi_clk = ~espi_clk;
			if(i%2 != 0)
				data_out = {data_out[3:0],espi_data};
			else
				data_out = data_out;
		end
	endtask
endclass

module eSPI_Harness();

// ---------------------------------
// Device under test
// ---------------------------------
`ifdef PERIPHERAL
eSPI_slave dut
(
	.sys_clk			(sys_clk			),
	.sys_rst_n			(sys_rst_n			),

	.espi_clk			(espi_clk			),
	.espi_cs			(espi_cs			),
	.espi_data			(espi_data			),
	.espi_rst_n			(espi_rst_n			),
	
	.status_avail		(status_avail		),

	.cycle_to_ip		(cycle_to_ip		),
	.tag_to_ip			(tag_to_ip			),
	.length_to_ip		(length_to_ip		),
	.addr_to_ip			(addr_to_ip			),
	.code_to_ip			(code_to_ip			),
	.specific_to_ip		(specific_to_ip		),	
	.data_req			(data_req			),
	.data_to_ip			(data_to_ip			),
                                            
	.command_valid		(command_valid		),
	.command			(wr_command			),
	.addr_valid			(addr_valid			),
	.address			(address			),
	.hdr_valid			(hdr_valid			),
	.cycle				(cycle				),
	.tag				(tag				),
	.length				(length				),
	.message_valid		(message_valid		),
	.message_code		(message_code		),
	.message_specific	(message_specific	),
	.data_valid			(data_valid			),
	.data_from_ip		(data_from_ip		),

	.error_en			(error_en			),
	.error_data			(error_data			),
                                            
	.response_wait		(response_wait		),
	.response_defer		(response_defer		)
);

`ifdef FSDB
initial
begin
	$fsdbDumpfile("tb_peripheral.fsdb");
	$fsdbDumpvars;
end
`endif

`endif

`ifdef VIRTUAL_WIRE
eSPI_slave dut
(
	.sys_clk			(sys_clk			),
	.sys_rst_n			(sys_rst_n			),

	.espi_clk			(espi_clk			),
	.espi_cs			(espi_cs			),
	.espi_data			(espi_data			),
	.espi_rst_n			(espi_rst_n			),

	.status_avail		(status_avail[2]	),
                                            
	.count_to_ip		(count_to_ip		),
	.vw_index_to_ip		(vw_index_to_ip		),
	.vw_data_to_ip		(vw_data_to_ip		),
                                            
	.command_valid		(command_valid		),
	.command			(wr_command			),
//	.addr_valid			(addr_valid			),
//	.address			(address			),
	.vw_cnt_valid		(vw_cnt_valid		),
	.count				(count				),
	.vw_group_valid		(vw_group_valid		),
	.vw_index			(vw_index			),
	.vw_data			(vw_data			),

	.vw_irq0			(vw_irq0			),
	.vw_irq1			(vw_irq1			),
	.slp_s3_n			(slp_s3_n			),
	.slp_s4_n			(slp_s4_n			),
	.slp_s5_n			(slp_s5_n			),
	.oob_rst_warn		(oob_rst_warn		),
	.sus_stat_n			(sus_stat_n			),
	.pltrst_n			(pltrst_n			),
	.pme_n				(pme_n				),
	.wake_n				(wake_n				),
	.oob_rst_ack		(oob_rst_ack		),
	.slave_boot_load_status	(slave_boot_load_status),
	.error_nonfatal		(error_nonfatal		),
	.error_fatal		(error_fatal		),
	.slave_boot_load_done	(slave_boot_load_done),
	.host_rst_ack		(host_rst_ack		),
	.pcin_n				(pcin_n				),
	.smi_n				(smi_n				),
	.sci_n				(sci_n				),
	.nmiout_n			(nmiout_n			),
	.smiout_n			(smiout_n			),
	.host_rst_warn		(host_rst_warn		),

	.error_en			(error_en			),
	.error_data			(error_data			),
                                            
	.response_wait		(response_wait		)
);

`ifdef FSDB
initial
begin
	$fsdbDumpfile("tb_virtual_wire.fsdb");
	$fsdbDumpvars;
end
`endif
`endif

`ifdef OOB
eSPI_slave dut
(
	.sys_clk			(sys_clk			),
	.sys_rst_n			(sys_rst_n			),

	.espi_clk			(espi_clk			),
	.espi_cs			(espi_cs			),
	.espi_data			(espi_data			),
	.espi_rst_n			(espi_rst_n			),

	.status_avail		(status_avail		),
                                            
	.cycle_to_ip		(cycle_to_ip		),
	.tag_to_ip			(tag_to_ip			),
	.length_to_ip		(length_to_ip		),
	.SMBus_addr_to_ip	(SMBus_addr_to_ip	),
	.SMBus_cmd_to_ip	(SMBus_cmd_to_ip	),
	.SMBus_cnt_to_ip	(SMBus_cnt_to_ip	),
	.data_req			(data_req			),
	.data_to_ip			(data_to_ip			),
                                            
	.command_valid		(command_valid		),
	.command			(wr_command			),
	.addr_valid			(addr_valid			),
	.address			(address			),
	.hdr_valid			(hdr_valid			),
	.cycle				(cycle				),
	.tag				(tag				),
	.length				(length				),
	.SMBus_hdr_valid	(SMBus_hdr_valid	),
	.SMBus_target_addr	(SMBus_target_addr	),
	.SMBus_command		(SMBus_command		),
	.SMBus_byte_cnt		(SMBus_byte_cnt		),
	.data_valid			(data_valid			),
	.data_from_ip		(data_from_ip		),
	.error_en			(error_en			),
	.error_data			(error_data			),
                                            
	.response_wait		(response_wait		)
);

`ifdef FSDB
initial
begin
	$fsdbDumpfile("tb_OOB.fsdb");
	$fsdbDumpvars;
end
`endif
`endif

`ifdef FLASH
eSPI_slave dut
(
	.sys_clk			(sys_clk			),
	.sys_rst_n			(sys_rst_n			),

	.espi_clk			(espi_clk			),
	.espi_cs			(espi_cs			),
	.espi_data			(espi_data			),
	.espi_rst_n			(espi_rst_n			),

	.status_avail		(status_avail		),
                                            
	.cycle_to_ip		(cycle_to_ip		),
	.tag_to_ip			(tag_to_ip			),
	.length_to_ip		(length_to_ip		),
	.addr_to_ip			(addr_to_ip			),
	.data_req			(data_req			),
	.data_to_ip			(data_to_ip			),
                                            
	.command_valid		(command_valid		),
	.command			(wr_command			),
	.addr_valid			(addr_valid			),
	.address			(address			),
	.hdr_valid			(hdr_valid			),
	.cycle				(cycle				),
	.tag				(tag				),
	.length				(length				),
	.data_valid			(data_valid			),
	.data_from_ip		(data_from_ip		),

	.error_en			(error_en			),
	.error_data			(error_data			),
                                            
	.response_wait		(response_wait		)
);

`ifdef FSDB
initial
begin
	$fsdbDumpfile("tb_flash.fsdb");
	$fsdbDumpvars;
end
`endif
`endif

`ifdef ALL_CHANNEL
eSPI_slave dut
(
	.sys_clk			(sys_clk			),
	.sys_rst_n			(sys_rst_n			),

	.espi_clk			(espi_clk			),
	.espi_cs			(espi_cs			),
	.espi_data			(espi_data			),
	.espi_rst_n			(espi_rst_n			),

	.status_avail		(status_avail		),
                                            
	.cycle_to_ip		(cycle_to_ip		),
	.tag_to_ip			(tag_to_ip			),
	.length_to_ip		(length_to_ip		),
	.code_to_ip			(code_to_ip			),
	.specific_to_ip		(specific_to_ip		),
	.count_to_ip		(count_to_ip		),
	.vw_index_to_ip		(vw_index_to_ip		),
	.vw_data_to_ip		(vw_data_to_ip		),
	.addr_to_ip			(addr_to_ip			),
	.SMBus_addr_to_ip	(SMBus_addr_to_ip	),
	.SMBus_cmd_to_ip	(SMBus_cmd_to_ip	),
	.SMBus_cnt_to_ip	(SMBus_cnt_to_ip	),
	.data_req			(data_req			),
	.data_to_ip			(data_to_ip			),
                                            
	.command_valid		(command_valid		),
	.command			(wr_command			),
	.addr_valid			(addr_valid			),
	.address			(address			),
	.hdr_valid			(hdr_valid			),
	.cycle				(cycle				),
	.tag				(tag				),
	.length				(length				),
	.message_valid		(message_valid		),
	.message_code		(message_code		),
	.message_specific	(message_specific	),
	.vw_cnt_valid		(vw_cnt_valid		),
	.count				(count				),
	.vw_group_valid		(vw_group_valid		),
	.vw_index			(vw_index			),
	.vw_data			(vw_data			),
	.SMBus_hdr_valid	(SMBus_hdr_valid	),
	.SMBus_target_addr	(SMBus_target_addr	),
	.SMBus_command		(SMBus_command		),
	.SMBus_byte_cnt		(SMBus_byte_cnt		),
	.data_valid			(data_valid			),
	.data_from_ip		(data_from_ip		),

	.vw_irq0			(vw_irq0			),
	.vw_irq1			(vw_irq1			),
	.slp_s3_n			(slp_s3_n			),
	.slp_s4_n			(slp_s4_n			),
	.slp_s5_n			(slp_s5_n			),
	.oob_rst_warn		(oob_rst_warn		),
	.sus_stat_n			(sus_stat_n			),
	.pltrst_n			(pltrst_n			),
	.pme_n				(pme_n				),
	.wake_n				(wake_n				),
	.oob_rst_ack		(oob_rst_ack		),
	.slave_boot_load_status	(slave_boot_load_status),
	.error_nonfatal		(error_nonfatal		),
	.error_fatal		(error_fatal		),
	.slave_boot_load_done	(slave_boot_load_done),
	.host_rst_ack		(host_rst_ack		),
	.pcin_n				(pcin_n				),
	.smi_n				(smi_n				),
	.sci_n				(sci_n				),
	.nmiout_n			(nmiout_n			),
	.smiout_n			(smiout_n			),
	.host_rst_warn		(host_rst_warn		),

	.error_en			(error_en			),
	.error_data			(error_data			),
                                            
	.response_wait		(response_wait		),
	.response_defer		(response_defer		)
);

`ifdef FSDB
initial
begin
	$fsdbDumpfile("tb_all.fsdb");
	$fsdbDumpvars;
end
`endif

`endif
// ---------------------------------
// Clock and Reset generation
// ---------------------------------
initial
begin
	sys_clk = 1'b1;
	#12.5ns sys_clk = 1'b0;
	forever #9.6ns sys_clk = ~sys_clk;
end

assign espi_data = (wr_valid == 1'b1) ? send_data : 4'bzzzz;

always@(data_req)
begin
	if(data_req)
		data_to_ip <= {$random} % 8'hff;
	else
		data_to_ip <= data_to_ip;
end

//initial #100_000_000_000 $finish;

endmodule 
`endif
